home *** CD-ROM | disk | FTP | other *** search
- #!/usr/local/export/bin/perl
- ## Make a gif "transparent"
- ##
- ## Jeffrey Friedl
- ## jfriedl@omrongw.wg.omron.co.jp
- ## 15 July 1994
- ##
- ## I wrote this because people ask for something like this all the time.
- ## I just learned the format of GIFs a week ago, so this will likely be
- ## lacking in many respects.
- ##
- ## Usage:
- ##
- ## transgif [colornum] regular.gif > transparent.gif
- ## or
- ## cat regular.gif | transgif [colornum] transparent.gif
- ##
- ## COLORNUM is the index of the color entry to make transparent, and
- ## defaults to zero. For those that like the looks of it, you can put
- ## a leading '-'.
- ##
- ## Idea for the future: let the color be defined as R-G-B and select the
- ## closest color from the colormap and use that.
- ##
-
- $color = 0;
- if (@ARGV && $ARGV[0] =~ m/^-?(\d+)/) {
- $color = $1;
- shift;
- }
-
- die "too many args; usage: $0 [colornum] [file]\n" if @ARGV > 1;
- if (@ARGV == 0) {
- &giftrans(*STDIN, *STDOUT, $color);
- } else {
- open(INPUT, $file =shift) || die "$0: couldn't open [$file] for input\n";
- &giftrans(*INPUT, *STDOUT, $color);
- close(INPUT);
- }
-
- ##
- ## Given indirect references to two filehandles, pass the file from
- ## one to the other, changing nothing unless it's a GIF that we know
- ## how to deal with, and if so do so.
- ##
- ## This is written rather verbosely for the sake of clarity... speed not
- ## much of an issue for something like this, and the difference is minimal
- ## anyway.
- ##
- sub giftrans
- {
- local(*IN, *OUT, $color) = @_;
- $color = 0 if !defined $color;
- local($header, $color_table, $nextblock, $buffer) = ('') x 4;
-
- ## The header looks like:
- ## byte 0 - 5: "GIF89a" or "GIF87a"
- ## byte 6, 7: width (low order first)
- ## byte 8, 9: height (low order first)
- ## byte 10: various flags
- ## byte 11: background color index
- ## byte 12: aspect ratio
- sysread(IN, $header, 13) || die "sysread header";
- substr($header, 0, 6) = 'GIF89a' if substr($header,0,6) eq 'GIF87a';
- print OUT $header;
-
- if (substr($header, 0, 6) ne 'GIF89a') {
- print STDERR "don't know input filetype, passing unchanged\n";
- } else {
- ##
- ## Look at flags:
- ## High bit is global colormap indicator.
- ## Value_in_next_three_bits + 1 == number of bits per pixel.
- ## Next bit indicates if color map is sorted by importance.
- ## (1 + 2 ** (Value_in_final_three_bits + 1)) == size of colormap.
- ##
- local($flags) = ord(substr($header, 10, 1));
- local($has_global_colormap) = $flags & 0x80;
-
- ## Copy over the colormap if need be.
- if ($has_global_colormap)
- {
- local($bits_per_color) = 1 + ($flags & 0x07);
- local($color_tbl_size) = 3 * (1 << $bits_per_color);
-
- sysread(IN, $color_table, $color_tbl_size) || die "sysread color";
- print OUT $color_table;
- }
-
- ##
- ## The next 8 bytes will either be an already-there graphic-extension
- ## block, or something else that we'll not care about. In the latter
- ## case, we'll add a graphic-extension block saying "color such-and-
- ## such is transparent". If there's already one there, we'll just
- ## ensure that it says that.
- ##
- sysread(IN, $nextblock, 8) || die "sysread nextblock";
- local($extension, $label) = unpack('CC', $nextblock);
- ## If extension is 0x21 and label is 0xf9, that's the magic tha means
- ## there's already a graphic extension there.
- if ($extension == 0x21 && $label == 0xf9) {
- substr($nextblock, 3, 1) = pack('C', 1|substr($nextblock, 3, 1));
- substr($nextblock, 6, 1) = pack('C', $color);
- } else {
- print OUT pack('CCC CCCC C',
- 0x21, ## magic: "Extension Introducer"
- 0xf9, ## magic: "Graphic Control Label"
- 4, ## bytes in block (between here and terminator)
- 0x01, ## indicates that 'transparet index' is given
- 0, 0, ## delay time.
- $color, ## index of "transparent" color.
- 0x00); ## terminator.
- }
- print OUT $nextblock;
- }
-
- ## Now just pass the rest of the file over unchanged.
-
- print OUT $buffer while sysread(IN, $buffer, 4096);
- close(IN);
- close(OUT);
- }